﻿using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;



using Utilities = OpenTK.Platform.Utilities;

namespace ArtemisTest
{

    #region SystemManager

    public class SystemsManager
    {
        #region SystemsDeclarations
        public EntitySystem entitySystem;
        public EntityFactory entityFactory;
        public MovementSystem movementSystem;
        //public DrawingSystem drawingSystem;
        public ScriptSystem scriptSystem;
        public SoundSystem2 soundSystem;
        public PhysicsSystem physicsSystem;
        public InputSystem inputSystem;
        public ModelDrawingSystem modelSystem;
        public TextureSystem textureSystem;
        //SoundSystem soundSystem;
        #endregion

        public void LoadSystems(GameWindow w)
        {
            entitySystem = new EntitySystem();
            entityFactory = new EntityFactory();
            scriptSystem = new ScriptSystem(entitySystem);
            movementSystem = new MovementSystem(entitySystem,scriptSystem);
            //drawingSystem = new DrawingSystem(entitySystem, w, scriptSystem);
            soundSystem = new SoundSystem2(entitySystem, scriptSystem);
            physicsSystem = new PhysicsSystem(entitySystem, scriptSystem);
            inputSystem = new InputSystem(entitySystem, scriptSystem);
            modelSystem = new ModelDrawingSystem(entitySystem, scriptSystem, w);
            textureSystem = new TextureSystem();

            soundSystem.Init();
            movementSystem.Init();
            //drawingSystem.Init();
            inputSystem.Init(w);
            modelSystem.Init(textureSystem);
        }

        public void LoadData()
        {
            for (int i = 0; i < 16; i++)
            {
                entityFactory.CreateScenery(i * 32, 0, 1, entitySystem);
                entityFactory.CreateScenery(0, (i + 1) * 32, 2, entitySystem);
                entityFactory.CreateScenery(2 * 32, (i + 2) * 32, 2, entitySystem);
            }

            Random r = new Random();

            long en = entityFactory.GetNewEntity(-1);
            Position p = new Position(en, 32, 32);
            Img im = new Img(en, 0, System.Drawing.Color.White);
            Bounds b = new Bounds(en, 32, 32);
            entitySystem.Components.AddComponent(p, en);  //add position
            entitySystem.Components.AddComponent(im, en); //add image
            entitySystem.Components.AddComponent(b, en);  //add bounds

            Sound s = new Sound(en);
            SoundPlayer sp = new SoundPlayer(en);
            entitySystem.Components.AddComponent(s, en);
            entitySystem.Components.AddComponent(sp, en);

            //soundSystem.InitSound(ref s, ref sp, new string[] { "sound\\Battle_Jazz.ogg" }.ToList(),
            //    new float[] { 0.5f }.ToList(), new bool[] { false }.ToList());

            //soundSystem.SetSoundToPlay(ref sp, 0);
            KeyboardKeyScript_MoveWithVel kkseg = new KeyboardKeyScript_MoveWithVel(en,this );//entitySystem
            entitySystem.Components.AddComponent(kkseg, en);
            entitySystem.Components.AddComponent(new Dynamic(en), en);
            entitySystem.AddEntity(en);
        }

        public void Update(FrameEventArgs e, GameWindow w)
        {
            inputSystem.PreUpdate(e.Time, w.Mouse, w.Keyboard);
            physicsSystem.PreUpdate(e.Time);

            modelSystem.PreUpdate(e.Time);
            movementSystem.Update(e.Time);
            scriptSystem.Update(e.Time);
            soundSystem.Update(e.Time);
        }
        public void Draw(FrameEventArgs e)
        {
            //drawingSystem.PreUpdate(e.Time);
            modelSystem.Update(e.Time,textureSystem);
            //drawingSystem.Update(e.Time);
            //drawingSystem.PostUpdate(e.Time);


        }
    }
    #endregion


    #region OpenTk
    public class SimpleWindow : GameWindow
    {
        const bool PRINT_MISS_CASTS = false;
        const bool PRINT_FPS = false;

        SystemsManager _manager = new SystemsManager(); 

        public SimpleWindow()
            : base(800, 600)
        {
            Keyboard.KeyDown += Keyboard_KeyDown;
        }

        #region Keyboard_KeyDown
        void Keyboard_KeyDown(object sender, KeyboardKeyEventArgs e)
        {
            if (e.Key == Key.Escape)
                this.Exit();

            if (e.Key == Key.F11)
                if (this.WindowState == WindowState.Fullscreen)
                    this.WindowState = WindowState.Normal;
                else
                    this.WindowState = WindowState.Fullscreen;
        }
        #endregion

        #region OnLoad
        protected override void OnLoad(EventArgs e)
        {
            //GL.ClearColor(Color.White);
            this.VSync = VSyncMode.Off;

            _manager.LoadSystems(this);

            _manager.LoadData();
        }

        #endregion

        #region OnResize
        protected override void OnResize(EventArgs e)
        {
            GL.Viewport(0, 0, Width, Height);

            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(0, 800, 600, 0, -10, 10);
            //GL.Ortho(-1.0, 1.0, -1.0, 1.0, 0.0, 4.0);
        }
        #endregion

        #region OnUpdateFrame
        protected override void OnUpdateFrame(FrameEventArgs e)
        {


            // System Updates
            _manager.Update(e, this);

            if (PRINT_MISS_CASTS) { Console.WriteLine("Miss Casts =" + Misc.GetComponentsNotFoundThisTick()); }
            Misc.ResetComponentsNotFoundThisTick();
            if (PRINT_FPS) { Console.WriteLine(this.RenderFrequency); }
        }
        #endregion

        #region OnRenderFrame
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            _manager.Draw(e);
        }
    }
        #endregion

    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            const bool CAP_FPS = false;

            using (SimpleWindow example = new SimpleWindow())
            {
                if (CAP_FPS) { example.Run(200, 200); }
                else
                { 
                    example.Run(); 
                }
            }
        }
    }
}